{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "mnist = tf.keras.datasets.mnist\n",
    "(train_images,train_labels),(test_images,test_labels) = mnist.load_data()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_images = train_images / 255.0\n",
    "test_images = test_images / 255.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_labels_ohe = tf.one_hot(train_labels,depth=10).numpy()\n",
    "test_labels_ohe = tf.one_hot(test_labels,depth = 10).numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [],
   "source": [
    "def runDNN(myW):\n",
    "    train_epochs = 10\n",
    "    batch_size = 30\n",
    "    model = tf.keras.models.Sequential()\n",
    "    model.add(tf.keras.layers.Flatten(input_shape = (28,28)))\n",
    "    model.add(tf.keras.layers.Dense(units=64,kernel_initializer=myI(myW),activation=\"relu\"))\n",
    "    model.add(tf.keras.layers.Dense(units=32,kernel_initializer='normal',activation='relu'))\n",
    "    model.add(tf.keras.layers.Dense(units=10,activation='softmax'))\n",
    "    model.compile(optimizer=\"Adam\",loss = tf.keras.losses.categorical_crossentropy,metrics=['accuracy'])\n",
    "    history = model.fit(train_images,train_labels_ohe,validation_split=0.2,batch_size = batch_size,verbose = 0)\n",
    "    loss = history.history[\"loss\"][0]\n",
    "    accuracy = history.history[\"accuracy\"][0]\n",
    "    weight = model.trainable_variables[0].numpy()\n",
    "    return loss,accuracy,weight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Individual:\n",
    "    def __init__(self) -> None:\n",
    "        pass\n",
    "    \n",
    "    def generateRandomly(self):\n",
    "        self.weight = numpy.random.rand(784,64)\n",
    "\n",
    "    def generatePrecisely(self,W):\n",
    "        self.weight = W\n",
    "\n",
    "    def recordLoss(self,loss):\n",
    "        self.loss = loss\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Group:\n",
    "\n",
    "    def __init__(self) -> None:\n",
    "        pass\n",
    "\n",
    "    def generateGroup(self,num):\n",
    "        self.weight = []\n",
    "        self.group = []\n",
    "        self.num = num\n",
    "        self.sumLoss = 0.0\n",
    "        self.minLoss = 10000000\n",
    "        for i in range(num):\n",
    "            individual = Individual()\n",
    "            individual.generateRandomly()\n",
    "            self.group.append(individual)\n",
    "        for i in range(num):\n",
    "            loss_,accuracy_, weight_ = runDNN(self.group[i].weight)\n",
    "            self.group[i].recordLoss(loss_)\n",
    "            if loss_ < self.minLoss:\n",
    "                self.bestWeight = weight_\n",
    "                self.minLoss = loss_\n",
    "\n",
    "\n",
    "    def select(self,num):\n",
    "        record = []\n",
    "        self.sumLoss = 0.0\n",
    "        for i in range(num):\n",
    "            self.sumLoss = self.sumLoss + self.group[i].loss\n",
    "            record.append(self.sumLoss)\n",
    "        record_ = [ad / self.sumLoss for ad in record]\n",
    "        nextgroup = []\n",
    "        for i in range(num):\n",
    "            r = numpy.random.random()\n",
    "            for j in range(num):\n",
    "                if r<record_[j]:\n",
    "                    nextgroup.append(self.group[j])\n",
    "                    break\n",
    "        self.group = nextgroup    \n",
    "\n",
    "        \n",
    "\n",
    "    def crossOver(self):\n",
    "        c1 = numpy.random.randint(0,self.num)\n",
    "        c2 = numpy.random.randint(0,self.num)\n",
    "        while c1 == c2:\n",
    "            c2 = numpy.random.randint(0,self.num)\n",
    "        individualShape = self.group[c1].weight.shape\n",
    "        individualSize = individualShape[0] * individualShape[1]\n",
    "        self.individualShape = individualShape\n",
    "        self.individualSize = individualSize\n",
    "        low = numpy.random.randint(0,individualSize)\n",
    "        high = numpy.random.randint(0,individualSize)\n",
    "        while low>=high:\n",
    "            high = numpy.random.randint(0,individualSize)\n",
    "        \n",
    "        c1Vector = self.group[c1].weight.reshape(-1)\n",
    "        c2Vector = self.group[c2].weight.reshape(-1)\n",
    "\n",
    "        for i in range(low,high):\n",
    "            a = c1Vector[i]\n",
    "            c1Vector[i] = c2Vector[i]\n",
    "            c2Vector[i] = a\n",
    "\n",
    "        c1NewWeight = c1Vector.reshape((individualShape[0],individualShape[1]))\n",
    "        c2NewWeight = c2Vector.reshape((individualShape[0],individualShape[1]))\n",
    "\n",
    "        self.group[c1].weight = c1NewWeight\n",
    "        self.group[c2].weight = c2NewWeight\n",
    "\n",
    "\n",
    "    def mutation(self,threshold):\n",
    "        for i in range(self.num):\n",
    "            r = numpy.random.random()\n",
    "            if r>threshold:\n",
    "                #只变异一个位置，可以根据需要更改\n",
    "                mutationLocation = numpy.random.randint(0,self.individualSize)\n",
    "                ciVector = self.group[i].weight.reshape(-1)\n",
    "                ciVector[mutationLocation] = numpy.random.random()\n",
    "                ciWeight = ciVector.reshape((self.individualShape[0],self.individualShape[1]))\n",
    "                self.group[i].weight = ciWeight\n",
    "        self.changeLoss()\n",
    "    \n",
    "    def changeLoss(self):\n",
    "        self.minLoss = 10000000\n",
    "        for i in range(self.num):\n",
    "            loss_, accuracy_,weight_ = runDNN(self.group[i].weight)\n",
    "            self.group[i].recordLoss(loss_)\n",
    "            self.weight.append(weight_)\n",
    "            if loss_ < self.minLoss:\n",
    "                self.bestWeight = weight_\n",
    "                self.minLoss = loss_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [],
   "source": [
    "class myI(tf.keras.initializers.Initializer):\n",
    "    def __init__(self,W):\n",
    "        self.W = W\n",
    "    def __call__(self, shape, dtype):\n",
    "        return self.W"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [],
   "source": [
    "iterateTime = 10\n",
    "groupSize = 10\n",
    "G = Group()\n",
    "G.generateGroup(groupSize)\n",
    "Losses = []\n",
    "Weights = []\n",
    "Losses.append(G.minLoss)\n",
    "Weights.append(G.bestWeight)\n",
    "for i in range(iterateTime):\n",
    "    G.select(groupSize)\n",
    "    G.crossOver()\n",
    "    G.mutation(0.1)\n",
    "    Losses.append(G.minLoss)\n",
    "    Weights.append(G.bestWeight)\n",
    "minLoss_ = Losses[0]\n",
    "bestWeight_ = Weights[0]\n",
    "for i in range(iterateTime+1):\n",
    "    if Losses[i] < minLoss_:\n",
    "        minLoss_ = Losses[i]\n",
    "        bestWeight_ = Weights[i]\n",
    "lastLoss, lastAcc, lastWeight = runDNN(bestWeight_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.3091996908187866"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lastLoss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.5970208048820496"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lastAcc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.9921456 , 0.47206622, 0.18245605, ..., 0.9336696 , 0.28816754,\n",
       "        0.714535  ],\n",
       "       [0.6943197 , 0.6210467 , 0.884081  , ..., 0.26906177, 0.3274158 ,\n",
       "        0.6317038 ],\n",
       "       [0.8638505 , 0.00330805, 0.46500114, ..., 0.07368544, 0.7442812 ,\n",
       "        0.05436969],\n",
       "       ...,\n",
       "       [0.4402151 , 0.9551317 , 0.17194736, ..., 0.71571684, 0.5026774 ,\n",
       "        0.64454925],\n",
       "       [0.04436841, 0.65338457, 0.34327778, ..., 0.7995557 , 0.21138372,\n",
       "        0.02636773],\n",
       "       [0.673357  , 0.03274895, 0.9805429 , ..., 0.6191446 , 0.09476824,\n",
       "        0.80374163]], dtype=float32)"
      ]
     },
     "execution_count": 99,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lastWeight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
